package com.chaos.springdemo.json;

import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Parameter;
import java.util.Map;

import org.springframework.boot.json.GsonJsonParser;
import org.springframework.core.convert.support.DefaultConversionService;

import com.google.common.base.Defaults;
import com.google.common.base.Preconditions;
import com.google.common.base.Strings;

import lombok.RequiredArgsConstructor;
import lombok.ToString;

public class JsonToBean {
    private static final DefaultConversionService DEFAULT_CONVERSION_SERVICE = new DefaultConversionService();
    public static <T> T createBeanFromJson(String jsonStr, Class<T> type) {
        Preconditions.checkNotNull(type);
        Preconditions.checkArgument(!Strings.isNullOrEmpty(jsonStr));
        Constructor<?>[] constructors = type.getConstructors();
        Preconditions.checkArgument(constructors.length == 1);
        Constructor<?> theOne = constructors[0];
        Parameter[] parameters = theOne.getParameters();
        GsonJsonParser gsonJsonParser = new GsonJsonParser();
        Map<String, Object> map = gsonJsonParser.parseMap(jsonStr);
        Object[] values = new Object[parameters.length];
        for(int i = 0; i < parameters.length; i++){
            Parameter parameter = parameters[i];
            Class<?> targetValueType = parameter.getType();
            Object value = map.get(parameter.getName());
            if (value != null){
                Object convertedValue = DEFAULT_CONVERSION_SERVICE.convert(value, targetValueType);
                values[i] = convertedValue;
            }else {
                value = Defaults.defaultValue(targetValueType);
                values[i] = value;
            }
        }
        try {
            Object bean = theOne.newInstance(values);
            return DEFAULT_CONVERSION_SERVICE.convert(bean, type);
        } catch (InstantiationException | IllegalAccessException | InvocationTargetException e) {
            e.printStackTrace();
        }
        return null;
    }

    public static void main(String[] args) {
        String json = "{}";

        Person person = createBeanFromJson(json, Person.class);

        System.out.println(person);
    }

    @ToString()
    @RequiredArgsConstructor
    static class Person{
        @ToString.Include
        private final String name;

        @ToString.Include
        private final Integer age;
    }
}
